using UnityEngine;
using System.Collections;
using System.Configuration;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.IO;


public class SAMapManager : Singleton< SAMapManager > 
{
	//private Dictionary< int , SAMapData > mapDataDic = new Dictionary< int , SAMapData >();
	private Dictionary< int , GameObject > terrainDic = new Dictionary< int , GameObject >();
	private Dictionary< int , GameObject > buildingDic = new Dictionary< int , GameObject >();

	[ HideInInspector ] public int maxXGrid = 0;
	[ HideInInspector ] public int maxYGrid = 0;

	[ HideInInspector ] public int mapID = GameDefine.INVALID_ID;

	private int[] terrainIndex = null;
	private int[] buildingIndex = null;

	private SAMapData activeMapData = null;
	private Camera mainCamera = null;

	private SAMapGrid mapGrid = new SAMapGrid();

	private float mapSacle = 0.0f;
	private float maxXGridReal = 0.0f;
	private float maxYGridReal = 0.0f;
	private float maxHalfXGridReal = 0.0f;
	private float maxHalfYGridReal = 0.0f;


	[ HideInInspector ] public SAPlayer mainPlayer = null;


	[ HideInInspector ] public GameObject terrainLayer = null;
	[ HideInInspector ] public GameObject creatureLayer = null;

	[ HideInInspector ] public bool isLoead = false;

	[ HideInInspector ] public SAPathFinder pathFinder = new SAPathFinder();


	private int asyncLoadDelay = 0;

	public SAMapData getActiveMapData()
	{
		return activeMapData;
	}

	void Start()
	{
		if ( mInstance == null )
		{
			mInstance = this;
			
			// init here ,


			terrainLayer = GameObject.FindWithTag( "terrainLayer" );
			creatureLayer = GameObject.FindWithTag( "creatureLayer" );
			
			mainCamera = GameObject.FindWithTag( "MainCamera" ).camera;
			mainCamera.orthographicSize = 1.0f / GameSetting.activeRes.showSacle;


			mainPlayer = GameObject.FindWithTag( "MainPlayer" ).GetComponent< SAPlayer >();
			mainPlayer.creatuerData = GamePlayerData.instance.creatureData;
			mainPlayer.initPlayer();
			mainPlayer.updateAction();
			mainPlayer.setPos( GamePlayerData.instance.Pos.X , GamePlayerData.instance.Pos.Y );
			
			mapSacle = mainCamera.orthographicSize;
			maxXGridReal = mapSacle * GameSetting.activeRes.sizeInPixel.x;
			maxYGridReal = mapSacle * GameSetting.activeRes.sizeInPixel.y;
			maxHalfXGridReal = 0.5f * maxXGridReal + SAMapGrid.GridX;
			maxHalfYGridReal = 0.5f * maxYGridReal + SAMapGrid.GridY;
			
			maxXGrid = GameSetting.activeRes.maxXGrid;
			maxYGrid = GameSetting.activeRes.maxYGrid;

			loadMapAsync();
		}
		
		
	}

	IEnumerator loadMapCoroutine()
	{
		asyncLoadDelay++;

		if ( asyncLoadDelay == 1 ) 
		{
			// delay second..

			yield return new WaitForSeconds( 0.5f );
		}

		loadMap( GamePlayerData.instance.Pos.MapID );
		mapID = GamePlayerData.instance.Pos.MapID;

		// load mini mapui
		MapUIHandler.instance.setMapID( mapID );

		isLoead = true;

		GamePlayerData.instance.onLoadMap();

		LoadingUIHandler.instance.UnShow();

		yield return 1;
	}

	public void loadMapAsync()
	{
		asyncLoadDelay = 0;

		LoadingUIHandler.instance.Show();

		StartCoroutine( loadMapCoroutine() );
	}


	public int getIndex( int x , int y )
	{
		return y * activeMapData.maxX + x;
	}

	public int getXWithIndex( int index )
	{
		return index % activeMapData.maxX;
	}

	public int getYWithIndex( int index )
	{
		return index / activeMapData.maxX;
	}


	public void findPath( int x , int y )
	{
		mainPlayer.startMove( x , y );
	}

	public void updateMainPlayer( SAPlayer player )
	{
		if ( player == mainPlayer )
		{
			SAMapPos pos = player.getPos();

			moveMapReal( (int)pos.mapGrid.realPosX , (int)pos.mapGrid.realPosY );

			if ( !pos.mapGrid.checkPos( mapGrid ) ) 
			{
				moveMap( pos.mapGrid.posX , pos.mapGrid.posY );
			}
		}


	}


	void moveMapReal( int x , int y )
	{
		mainCamera.transform.localPosition = new Vector3( (float)x , (float)y , 0 );

		int maxX = activeMapData.maxX * SAMapGrid.GridXHalf + activeMapData.maxY * SAMapGrid.GridXHalf;
		int maxY = activeMapData.maxX * SAMapGrid.GridYHalf + activeMapData.maxY * SAMapGrid.GridYHalf;

		y += activeMapData.maxY * SAMapGrid.GridYHalf;

		MapUIHandler.instance.setMapXY( (float)x / (float)maxX , (float)y / (float)maxY );
	}


	void moveMap( int x , int y )
	{
		SAMapGrid gridTemp = new SAMapGrid();

		if ( activeMapData == null ) 
		{
			return;
		}

		mapGrid.setValue( x , y );

		int minX = x - maxXGrid + 1;
		int minY = y - maxYGrid + 1;

		int maxX = x + maxXGrid;
		int maxY = y + maxYGrid;

		if ( minX < 0 ) 
		{
			minX = 0;
		}
		if ( minY < 0 ) 
		{
			minY = 0;
		}
		if ( maxX >= activeMapData.maxX ) 
		{
			maxX = activeMapData.maxX - 1;
		}
		if ( maxY >= activeMapData.maxY ) 
		{
			maxY = activeMapData.maxY - 1;
		}

		int terrainCount = 0;
		int buildingCount = 0;

		if ( terrainIndex == null ) 
		{
			terrainIndex = new int[ maxXGrid * maxYGrid * 4 ];
		}
		if ( buildingIndex == null ) 
		{
			buildingIndex = new int[ maxXGrid * maxYGrid * 4 ];
		}

		for ( int i = minY ; i < maxY ; i++ )
		{
			for ( int j = minX ; j < maxX ; j++ )
			{
				gridTemp.setValue( j , i );

				float xo = gridTemp.realPosX - mapGrid.realPosX;
				float yo = gridTemp.realPosY - mapGrid.realPosY;

				if ( !( xo > -maxHalfXGridReal && xo < maxHalfXGridReal && 
				    yo > -maxHalfYGridReal && yo < maxHalfYGridReal ) )
				{
					continue;
				}

				int index = getIndex( j , i );


				if ( terrainDic.ContainsKey( index ) )
				{
					terrainIndex[ terrainCount ] = index;
					terrainCount++;

					continue;
				}

				if ( activeMapData.terrain[ index ] > 0 )
				{
					GameObject obj = SASprite.CreateTerrainSprite();
					SASprite sprite = obj.GetComponent< SASprite >();
					sprite.setTerrainID( activeMapData.terrain[ index ] );
					sprite.setPos( j , i );

					terrainDic.Add( index , obj );

					terrainIndex[ terrainCount ] = index;
					terrainCount++;
				}
			}
		}

		for ( int i = minY ; i < maxY ; i++ )
		{
			for ( int j = minX ; j < maxX ; j++ )
			{
				gridTemp.setValue( j , i );
				
				float xo = gridTemp.realPosX - mapGrid.realPosX;
				float yo = gridTemp.realPosY - mapGrid.realPosY;
				
				if ( !( xo > -maxHalfXGridReal && xo < maxHalfXGridReal && 
				       yo > -maxHalfYGridReal && yo < maxHalfYGridReal ) )
				{
					continue;
				}

				int index = getIndex( j , i );

				if ( buildingDic.ContainsKey( index ) )
				{
					buildingIndex[ buildingCount ] = index;
					buildingCount++;

					continue;
				}


				if ( activeMapData.building[ index ] > 55 )
				{
					SATexture texture = SATextureConfig.instance.getTerrainTexture( activeMapData.building[ index ] );

					GameObject obj = SASprite.CreateCreatureSprite();
					SASprite sprite = obj.GetComponent< SASprite >();
					sprite.setTerrainID( activeMapData.building[ index ] );
					sprite.setPos( j , i , true );

					if ( texture.flag == 45 || texture.flag == 1 ) 
					{
						sprite.transform.localPosition = new Vector3( sprite.transform.localPosition.x , 
						                                           	  sprite.transform.localPosition.y ,
						                                             terrainLayer.transform.localPosition.z - 1 );
					}

					buildingDic.Add( index , obj );
					
					buildingIndex[ buildingCount ] = index;
					buildingCount++;
				}
			}
		}

		int[] keys = terrainDic.Keys.ToArray();  
		for ( int i = 0 ; i < keys.Length ; i++ )
		{
			int index = keys[ i ];

			int x1 = getXWithIndex( index );
			int y1 = getYWithIndex( index );

			gridTemp.setValue( x1 , y1 );
			
			float xo = gridTemp.realPosX - mapGrid.realPosX;
			float yo = gridTemp.realPosY - mapGrid.realPosY;
			
			if ( !( xo > -maxHalfXGridReal && xo < maxHalfXGridReal && 
			       yo > -maxHalfYGridReal && yo < maxHalfYGridReal ) )
			{
				GameObject obj = terrainDic[ index ];
				SASprite.DestorySprite( obj );
				
				terrainDic.Remove( index );
			}
		}

		keys = buildingDic.Keys.ToArray();  
		for ( int i = 0 ; i < keys.Length ; i++ )
		{
			int index = keys[ i ];

			int x1 = getXWithIndex( index );
			int y1 = getYWithIndex( index );

			gridTemp.setValue( x1 , y1 );

			float xo = gridTemp.realPosX - mapGrid.realPosX;
			float yo = gridTemp.realPosY - mapGrid.realPosY;
			
			if ( !( xo > -maxHalfXGridReal && xo < maxHalfXGridReal && 
			       yo > -maxHalfYGridReal && yo < maxHalfYGridReal ) )
			{
				GameObject obj = buildingDic[ index ];
				SASprite.DestorySprite( obj );
				
				buildingDic.Remove( index );
			}
		}

	}

	void activeMap()
	{
		if ( activeMapData != null ) 
		{

		}



	}

	public int getBattleMap()
	{
		SAMapPos pos = mainPlayer.getPos();

		int index = getIndex( pos.mapGrid.posX , pos.mapGrid.posY );

		ushort mapid = activeMapData.terrain[ index ];

		return SABattleMapConfig.instance.getBattleMap( mapid );
	}


	void clearMap()
	{
		if ( activeMapData == null ) 
		{
			return;
		}

		foreach ( KeyValuePair< int , GameObject > kv in terrainDic )
		{
			GameObject obj = kv.Value;
			SASprite.DestorySprite( obj , true );
		}

		foreach ( KeyValuePair< int , GameObject > kv in buildingDic )
		{
			GameObject obj = kv.Value;
			SASprite.DestorySprite( obj , true );
		}

		terrainDic.Clear();
		buildingDic.Clear();

		activeMapData = null;

		isLoead = false;

		mapID = GameDefine.INVALID_ID;
	}


	void loadMap( int id )
	{
		clearMap();

		activeMapData = new SAMapData();

		string path = "Map/" + id.ToString() + ".mapz";
		
		FileStream stream = File.Open( GameSetting.StreamingAssetsPath + path , FileMode.Open , FileAccess.Read );
		
		if ( stream == null )
		{
			return;
		}

		byte[] com = new byte[ stream.Length ];
		stream.Read( com , 0 , (int)stream.Length );
		byte[] dcom = GameDefine.DeCompress( com );

		int pos = 0;

		activeMapData.maxX = BitConverter.ToUInt16( dcom , pos ); pos += 2;
		activeMapData.maxY = BitConverter.ToUInt16( dcom , pos ); pos += 2;	

		activeMapData.terrain = new ushort[ activeMapData.maxX * activeMapData.maxY ];
		activeMapData.building = new ushort[ activeMapData.maxX * activeMapData.maxY ];
		byte[] block = new byte[ activeMapData.maxX * activeMapData.maxY ];

		for ( int i = 0 ; i < activeMapData.maxY; i++ ) 
		{
			for ( int j = 0 ; j < activeMapData.maxX; j++ ) 
			{
				int index = i * activeMapData.maxX + j;
				int tID = BitConverter.ToUInt16( dcom , pos ); pos += 2;
				activeMapData.terrain[ index ] = (ushort)tID;

				SATexture texture = SATextureConfig.instance.getTerrainTexture( tID );

				if ( texture != null ) 
				{
					texture.initData();
					//texture.loadDataAsync();
				}

				if ( texture == null || ( texture.flag != 1 && texture.flag != 45 ) ) 
				{
					if ( texture != null && texture.flag > 0 ) 
					{
						block[ index ] = SAPathFinder.BLOCK1;
					}
					block[ index ] = SAPathFinder.BLOCK1;
				}
			}
		}


		for ( int i = 0 ; i < activeMapData.maxY; i++ ) 
		{
			for ( int j = 0 ; j < activeMapData.maxX; j++ ) 
			{
				int tID = BitConverter.ToUInt16( dcom , pos ); pos += 2;
				int index = i * activeMapData.maxX + j;

				activeMapData.building[ index ] = (ushort)tID;

				SATexture texture = SATextureConfig.instance.getTerrainTexture( tID );

				if ( texture != null ) 
				{
					texture.initData();
					//texture.loadDataAsync();
				}

				if ( texture != null && !( texture.flag == 1 || texture.flag == 45 || texture.flag == 46 ) ) 
				{
					for ( int i0 = 0 ; i0 < texture.s ; i0++ )
					{
						for ( int j0 = 0 ; j0 < texture.e ; j0++ )
						{
							index = ( -i0 + i ) * activeMapData.maxX + ( j0 + j );
							block[ index ] = SAPathFinder.BLOCK1;
						}
					}
				}

			}
		}

		//moveMap( activeMapData.maxX / 2, activeMapData.maxY / 2 );
		mainPlayer.setPos( GamePlayerData.instance.Pos.X , GamePlayerData.instance.Pos.Y );
		updateMainPlayer( mainPlayer );

		pathFinder.initMap( activeMapData.maxX , activeMapData.maxY , block );

		Debug.Log( activeMapData.maxX + " " + activeMapData.maxY );

//		FileStream stream1 = File.Open( "/Users/fox/Desktop/opensa/test.txt" , FileMode.OpenOrCreate , FileAccess.Write );
//		StreamWriter sw = new StreamWriter( stream1 , Encoding.Default );
//		for (int i = 0; i < block.Length; i++ )
//		{
//			sw.Write( block[ i ] );
//		}
//		sw.Close();

		stream.Close();
	}

	
}


